Pinvon's Blog

所见, 所闻, 所思, 所想

Internet 控制报文协议(ICMP)

概述

IP 协议是一种不可靠无连接的协议, 当数据包经过多个网络传输后, 可能会出现目的主机不响应, 包拥塞, 包丢失等问题. 为了处理这些问题, 引入了 ICMP 协议. 通常我们认为 ICMP 是 IP 层的一个组成部分. 如图所示:

5.png

ICMP 报文格式

ICMP 报文有两种类型: 差错报文, 查询报文. 这两种报文的前 4 个字节的内容是相同的, 而接下来的字节内容则互不相同. 如图所示:

6.png

ICMP 报文类型

7.png

如上图所示, 8 位类型字段和 8 位代码字段共同决定了具体的 ICMP 报文类型(差错报文和查询报文只是最粗的分类, 在差错报文里面, 又细分了许多类型, 类型字段和代码字段共同决定了最具体的类型).

为什么不能直接分成查询报文和差错报文?

因为对于差错报文, 有时需要特殊处理, 比如, 对于一个 ICMP 差错报文进行响应时, 永远不会生成另一份 ICMP 差错报文. 因为 ICMP 报文也是不可靠的, 也可能会出错, 如果不进行限制, 可能会出现因为一个差错而产生另一个差错的情况, 而另一个差错报文又产生了它的差错报文, 这样就无休无止了.

从图中可以看出, 类型字段为 0, 8, 9, 10, 13, 14, 15, 16, 17, 18 时, 表示查询报文, 类型字段为 3, 4, 5, 11, 12 时, 大部分表示的是差错报文.

不会产生差错报文的情况:

  • ICMP 差错报文(ICMP 查询报文可能会产生 ICMP 差错报文)
  • 目的地址是广播地址或多播地址的 IP 数据报
  • 作为链路层广播的数据报
  • 不是 IP 分片的第一个分片
  • 源地址不是单个主机的数据报(即源地址不能是零地址, 环回地址, 广播地址, 多播地址)

如果不对这些情况进行限制, 很可能会产生广播风暴.

ICMP 时间戳请求与应答

ICMP 时间戳请求允许系统向另一个系统查询当前的时间. 返回值可以有多种类型的参考. 比较建议的做法是返回自午夜(UTC)开始计算的毫秒数. 这种 ICMP 报文的好处是它提供了毫秒级的分辨率, 而利用其他方法从别的主机获取的时间只能提供秒级的分辨率. 但由于获取的时间是从午夜开始计算的毫秒数, 所以当前日期需要根据其他途径获取.

报文格式如图所示:

8.png

请求端填写的是发起时间戳, 然后发送报文. 响应端填写的是接收时间戳和传送时间戳(实际上大多数的实现都是把后两者设成相同的值). 发送端可以根据这三个字段来计算发送请求的时间和发送应答的时间.

在 《TCP/IP详解卷一》中举了一个例子, 编写程序给某主机发送 ICMP 时间戳请求. 结果如下:

9.png

其中, difference = recv - orig

而 rtt 是根据发送端发出的时间和发送端接收的时间来计算的.

如果信任 rtt 的值, 且认为 rtt 的值有一半用于传输请求, 一半用于传输响应. 那么, 如果要让发送端与响应端的时间一致, 发送端应这样调整: difference - rtt/2. 得到的值为正, 说明发送端慢了, 得到的值为负, 说明发送端快了.

Comments

使用 Disqus 评论
comments powered by Disqus